package com.ekalenchuk.module.controllers.authorization;

import java.io.IOException;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.social.connect.Connection;
import org.springframework.social.facebook.api.Facebook;
import org.springframework.social.facebook.api.FacebookProfile;
import org.springframework.social.facebook.connect.FacebookConnectionFactory;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.social.oauth2.GrantType;
import org.springframework.social.oauth2.OAuth2Operations;
import org.springframework.social.oauth2.OAuth2Parameters;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.ekalenchuk.module.config.SocialAppSettingsFacebookImpl;
import com.ekalenchuk.module.constants.PageConstants;
import com.ekalenchuk.module.constants.facebook.FacebookPermission;
import com.ekalenchuk.module.constants.facebook.FacebookResponseCode;
import com.ekalenchuk.module.exception.entity.NotFoundException;
import com.ekalenchuk.module.exception.facebook.FacebookAuthorizationException;

@Controller
public class FacebookController extends BaseSocialContoller<SocialAppSettingsFacebookImpl> {

	private static final long serialVersionUID = -5593516717455943346L;
	private static final Logger logger = LoggerFactory.getLogger(FacebookController.class);
	private final String FACEBOOK_APP_ID;
	private final String FACEBOOK_APP_SECRET;
	private final String FACEBOOK_CALLBACK_URL;

	public FacebookController() {
		super();
		this.setFbSettings(SocialAppSettingsFacebookImpl.getApplicationSettings());
		FACEBOOK_APP_ID = this.getFbSettings().getAppId();
		FACEBOOK_APP_SECRET = this.getFbSettings().getAppSecret();
		FACEBOOK_CALLBACK_URL = this.getFbSettings().getCallbackUrl();
	}

	@RequestMapping(value = "/fb/access.html")
	public void requestFbAccess(HttpServletRequest request, HttpServletResponse response, Map<String, Object> model) throws IOException {
		String authorizeUrl = buildFbAuthorizeUrl();
		response.sendRedirect(authorizeUrl);
	}

	@RequestMapping(value = "/fb/fbcallback.html")
	public String processFbResponse(HttpServletRequest request, HttpServletResponse response, Map<String, Object> model) {
		try {
			FacebookProfile myProfile = getFacebookProfile(request);
			if (!getUserSession().isLoggedIn()) {
				getUserService().login(myProfile, getUserSession());
			}

		} catch (FacebookAuthorizationException e) {
			return facebookAuthorizationFailed(request);
		} catch (NotFoundException e) {
			return facebookAuthorizationFailed(request);
		}

		return PageConstants.START_REDIRECT;
	}

	private FacebookProfile getFacebookProfile(HttpServletRequest request) throws FacebookAuthorizationException {
		FacebookConnectionFactory connectionFactory = new FacebookConnectionFactory(FACEBOOK_APP_ID, FACEBOOK_APP_SECRET);
		OAuth2Operations oauthOperations = connectionFactory.getOAuthOperations();
		String authCode = request.getParameter(FacebookResponseCode.CODE);
		FacebookProfile myProfile = null;
		if (StringUtils.isNotBlank(authCode)) {
			AccessGrant accessGrant = oauthOperations.exchangeForAccess(authCode, FACEBOOK_CALLBACK_URL, null);
			Connection<Facebook> connection = connectionFactory.createConnection(accessGrant);
			myProfile = connection.getApi().userOperations().getUserProfile();
		} else {
			throw new FacebookAuthorizationException();
		}

		return myProfile;
	}
	
	private String facebookAuthorizationFailed(HttpServletRequest request) {
		String errorReason = request.getParameter(FacebookResponseCode.ERROR_REASON);//user_denied
		String error = request.getParameter(FacebookResponseCode.ERROR);//access_denied
		String errorDescr = request.getParameter(FacebookResponseCode.ERROR_DESCRIPTION);//The+user+denied+your+request.
		//TODO: implement
		logger.error(String.format("Registration is failed. Error: %s. Error reason: %s. Error description: %s.", error, errorReason, errorDescr));
		return PageConstants.START_REDIRECT;
	}

	private String buildFbAuthorizeUrl() {
		FacebookConnectionFactory connectionFactory = new FacebookConnectionFactory(FACEBOOK_APP_ID, FACEBOOK_APP_SECRET);
		OAuth2Operations oauthOperations = connectionFactory.getOAuthOperations();
		String authorizeUrl = oauthOperations.buildAuthorizeUrl(GrantType.AUTHORIZATION_CODE, getOAuth2Parameters());
		return authorizeUrl;
	}

	private OAuth2Parameters getOAuth2Parameters() {
		OAuth2Parameters params = new OAuth2Parameters();
		params.setRedirectUri(FACEBOOK_CALLBACK_URL);
		params.setScope(FacebookPermission.EMAIL);
		return params;
	}

}